RANDOM_CORRELATION
Overview
The RANDOM_CORRELATION function generates a random correlation matrix with user-specified eigenvalues. A correlation matrix is a symmetric, positive semi-definite matrix with ones on the diagonal that describes the pairwise linear relationships between variables. This function is useful in Monte Carlo simulations, portfolio risk analysis, and statistical modeling where a valid correlation structure with specific spectral properties is required.
This implementation uses the random_correlation distribution from SciPy, which follows the numerically stable algorithm developed by Davies and Higham. For more details, see the SciPy random_correlation documentation and the SciPy GitHub repository.
The algorithm constructs a random correlation matrix through a single O(N) similarity transformation to produce a symmetric positive semi-definite matrix, followed by a series of Givens rotations to scale the matrix so that its diagonal entries are all equal to one. This approach ensures numerical stability and guarantees that the resulting matrix has the exact eigenvalues provided as input.
For a valid correlation matrix, the eigenvalues must satisfy two conditions:
- All eigenvalues must be non-negative: \lambda_i \geq 0 for all i
- The eigenvalues must sum to the matrix dimension: \sum_{i=1}^{n} \lambda_i = n
The second constraint follows from the fact that a correlation matrix has unit diagonal, and the trace (sum of diagonal elements) equals the sum of eigenvalues. For example, to generate a 4×4 correlation matrix, you might use eigenvalues (0.5, 0.8, 1.2, 1.5) since 0.5 + 0.8 + 1.2 + 1.5 = 4.
The mathematical foundation for this algorithm is described in:
Davies, P. I. & Higham, N. J. (2000). “Numerically stable generation of correlation matrices and their factors.” BIT Numerical Mathematics, 40(4), 640–651.
This example function is provided as-is without any representation of accuracy.
Excel Usage
=RANDOM_CORRELATION(eigenvalues)
eigenvalues(list[list], required): 2D column array of non-negative eigenvalues. Must sum to the number of eigenvalues (matrix dimension).
Returns (list[list]): 2D random correlation matrix, or error message string.
Examples
Example 1: Basic 2x2 identity eigenvalues
Inputs:
| eigenvalues |
|---|
| 1 |
| 1 |
Excel formula:
=RANDOM_CORRELATION({1;1})
Expected output:
"non-error"
Example 2: 3x3 matrix with identity eigenvalues
Inputs:
| eigenvalues |
|---|
| 1 |
| 1 |
| 1 |
Excel formula:
=RANDOM_CORRELATION({1;1;1})
Expected output:
"non-error"
Example 3: 2x2 matrix with eigenvalues 1.5 and 0.5
Inputs:
| eigenvalues |
|---|
| 1.5 |
| 0.5 |
Excel formula:
=RANDOM_CORRELATION({1.5;0.5})
Expected output:
"non-error"
Example 4: 2x2 matrix with eigenvalues 0.7 and 1.3
Inputs:
| eigenvalues |
|---|
| 0.7 |
| 1.3 |
Excel formula:
=RANDOM_CORRELATION({0.7;1.3})
Expected output:
"non-error"
Python Code
from scipy.stats import random_correlation as scipy_random_correlation
def random_correlation(eigenvalues):
"""
Generates a random correlation matrix with specified eigenvalues.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.random_correlation.html
This example function is provided as-is without any representation of accuracy.
Args:
eigenvalues (list[list]): 2D column array of non-negative eigenvalues. Must sum to the number of eigenvalues (matrix dimension).
Returns:
list[list]: 2D random correlation matrix, or error message string.
"""
def to2d(x):
return [[x]] if not isinstance(x, list) else x
eigenvalues = to2d(eigenvalues)
if not isinstance(eigenvalues, list) or len(eigenvalues) < 2:
return "Invalid input: eigenvalues must be a 2D list with at least two rows."
# Flatten 2D list to 1D list
try:
flat_eigs = [float(row[0]) for row in eigenvalues]
except Exception:
return "Invalid input: eigenvalues must be a 2D list of floats."
if any(e < 0 for e in flat_eigs):
return "Invalid input: all eigenvalues must be non-negative."
n = len(flat_eigs)
if not abs(sum(flat_eigs) - n) < 1e-8:
return "Invalid input: sum of eigenvalues must equal the number of eigenvalues."
try:
mat = scipy_random_correlation(flat_eigs).rvs()
except Exception as e:
return f"scipy.stats.random_correlation error: {e}"
# Convert numpy array to 2D list of floats
result = [[float(x) for x in row] for row in mat.tolist()]
return result